package com.cenxi.common.aspect;
import com.cenxi.common.aspect.annotation.Permissions;
import com.cenxi.common.aspect.annotation.PermissionsService;
import com.cenxi.common.constants.TokenConstants;
import com.cenxi.common.exceptions.ServiceException;
import com.cenxi.common.util.JwtUtils;
import com.cenxi.common.util.SecurityUtils;
import com.cenxi.common.util.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * @Author cenxi
 * @Date 2023/6/16 17:59
 * @Version 1.0
 */
@Aspect
@Component
@Slf4j
public class PreAuthorizeAspect {
    /**
     * 构建
     */
    public PreAuthorizeAspect() {
    }

    /**
     * 定义AOP签名 (切入所有使用鉴权注解的方法)
     */
    public static final String POINTCUT_SIGN = "@annotation(com.cenxi.common.aspect.annotation.Permissions)";

    /**
     * 声明AOP签名
     */
    @Pointcut(POINTCUT_SIGN)
    public void pointcut() {
    }

    /**
     * 环绕切入
     *
     * @param joinPoint 切面对象
     * @return 底层方法执行后的返回值
     * @throws Throwable 底层方法抛出的异常
     */
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 注解鉴权
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        try {
            checkMethodAnnotation(signature.getMethod());
            // 执行原有逻辑
            return joinPoint.proceed();
        } catch (Throwable e) {
            throw e;
        }
    }

    /**
     * 对一个Method对象进行注解检查
     */
    public void checkMethodAnnotation(Method method) {
        Permissions annotation = method.getAnnotation(Permissions.class);
        PermissionsService permissionsService = SpringUtils.getBean(PermissionsService.class);
        //获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        //从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        String headerToken = request.getHeader(TokenConstants.AUTHENTICATION);
//        String headerToken = SecurityUtils.getToken();
        Assert.notNull(request, "request->对象为空");
        Assert.notNull(headerToken, "token为空");
        if (Boolean.TRUE.equals(permissionsService.Authentication(JwtUtils.getUserId(headerToken), annotation.value()))) {
            log.info("权限校验失败,url: {}", request.getRequestURI());
            throw new ServiceException("操作无权限");
        }
        log.info("权限校验成功");
    }
}
